#ifndef __tenacitas_log__level__h__
#define __tenacitas_log__level__h__



/** @file
    In this file is implemented tenacitas::log::level class */


/** todo */

// ==> C++ Headers
#include <cstdint>
#include <string>
#include <sstream>

// ==> 3rds Headers
#include <boost/thread/thread.hpp>

// ==> Our Headers
#include <tenacitas.exception/exception.h>

// ==> Namespaces
using namespace std;

// ==> Macro Contants

// ==> Macro Commands


/** namespace of the organization */
namespace tenacitas {

    /** ==> namespace of the project */
    namespace log {

        // ==> Typedefs 

        // ==> Pre-Declarations

        // ==> Attributes 

        // ==> Functions
        
        // ==> Classes

        /** Levels for logging messages

            There are 6 levels of logging defined: trace, debug, info, warn, error
            and critical. @p trace is the lowest and @p critical is the highest
            level

            <b>A word to the programmer user</b>
            You should use the tenacitas::log::level::trace,
            tenacitas::log::level::debug, tenacitas::log::level::info,
            tenacitas::log::level::warn, tenacitas::log::level::error or
            tenacitas::log::level::critical objects to define the log level
            you want to use.
            @nosubgrouping 
        */
        class level {

        public:

            //  ==> level - Public Constructors

            /** Copy constructor */
            inline level( const level & p_level );

            /** Destructor */
            inline ~level( );

            //  ==> level - Public Accessors 

            /** Informs a string corresponding a log level object

                @throw tenacitas::exception::exception
            */
            inline std::string str( ) const;

            //  ==> level - Public Processors -

            /** Creates a log level object based on a string

             @throw tenacitas::exception::exception
            */
            inline static const level & create( const std::string & p_str );

            //  ==> level - Public Operators 

            /** assignment */
            inline level & operator = ( const level & p_level );

            /** equal-to */
            inline bool operator == ( const level & p_level ) const;            

            /** not-equal-to */
            inline bool operator != ( const level & p_level ) const;
            
            /** greater-than-or-equal-to */
            inline bool operator >= ( const level & p_level ) const;

            /** greater-than not allowed */
            inline bool operator > ( const level & ) const = delete;

            /** less-than-or-equal-to */
            inline bool operator <= ( const level & p_level ) const;

            /** less-than not allowed */
            inline bool operator < ( const level & ) const = delete;

            //  ==> level - Public Attributes -

            /** Only posssibe log level values - trace */
            static const level trace;

            /** Only posssibe log level values - debug */
            static const level debug;

            /** Only posssibe log level values - info */
            static const level info;

            /** Only posssibe log level values - warn */
            static const level warn;

            /** Only posssibe log level values - error */
            static const level error;

            /** Only posssibe log level values - critical */
            static const level critical;

        private:
            //  ==> level - Public Internal Types

            /** Type for the internal level of the log */
            typedef int16_t value;

            //  ==> level - Private Constructors

            /** Constructor */
            level( value p_value )
            : m_value( p_value ) { }

            //  ==> level - Private Attributes 

            /** numeric value for a log level */
            value m_value;
        };
    }
}

// =============================================================================
//                     I M P L E M E N T A T I O N
// =============================================================================

using namespace tenacitas::log;

// -----------------------------------------------------------------------------
level::
level( const level & p_level )
    : m_value( p_level.m_value ) {}
            
// -----------------------------------------------------------------------------
level::
~level( ) {}

// -----------------------------------------------------------------------------
std::string
level::
str( ) const {
    if ( m_value == trace.m_value ) { return "trace"; }
    if ( m_value == debug.m_value ) { return "debug"; }
    if ( m_value == info.m_value ) { return "info"; }
    if ( m_value == warn.m_value ) { return "warn"; }
    if ( m_value == error.m_value ) { return "error"; }
    if ( m_value == critical.m_value ) { return "critical"; }

    std::stringstream l_stream;
    l_stream << m_value << " is not a valid log value";

    tenacitas::exception::exception l_ex =
        make_tenacitas_exception( l_stream.str( ) );
    throw ( l_ex );
}

// -----------------------------------------------------------------------------
const level &
level::
create( const std::string & p_str ) {
    if ( p_str == "trace" ) { return trace; }
    if ( p_str == "debug" ) { return debug; }
    if ( p_str == "info" ) { return info; }
    if ( p_str == "warn" ) { return warn; }
    if ( p_str == "error" ) { return error; }
    if ( p_str == "critical" ) { return critical; }

    std::stringstream l_stream;
    l_stream << "'" << p_str << "' is an invalid string for a "
        "'tenacitas::log::level' value";
                
    tenacitas::exception::exception
        l_ex( make_tenacitas_exception( l_stream.str( ) ) ); 
    throw ( l_ex );
}

// -----------------------------------------------------------------------------
level &
level::
operator = ( const level & p_level ) {
    if ( this != & p_level ) {
        m_value = p_level.m_value;
    }
    return *this;
}

// -----------------------------------------------------------------------------
bool
level::
operator == ( const level & p_level ) const {
    return m_value == p_level.m_value;
}

// -----------------------------------------------------------------------------
bool
level::
operator != ( const level & p_level ) const {
    return m_value != p_level.m_value;
}

// -----------------------------------------------------------------------------
bool
level::
operator >= ( const level & p_level ) const {
    return m_value >= p_level.m_value;
}

// -----------------------------------------------------------------------------
bool
level::
operator <= ( const level & p_level ) const {
    return m_value <= p_level.m_value;
}


#endif
